package tomoto.util;

import tomoto.assertion.ParamUtil;

/**
 * Two dimensional array of type T. This class provides final public fields to
 * allow clients to access to its contents directly. Elements are internally
 * stored in a linear array that is indexed by <code>x + (y * width)</code>.
 * 
 * @author Tomoto Shimizu Washio
 * 
 * @param <T> element type
 */
public class RectArray<T> {
	/** whether the parameter check is enabled */
	private static final boolean cs_paramCheckEnabled;
	static {
		cs_paramCheckEnabled = RectArray.class.desiredAssertionStatus();
	}
	
	/** width of the array */
	public final int width;
	/** height of the array */
	public final int height;
	/** elements */
	public final T[] elements;

	/**
	 * Creates an array.
	 * 
	 * @param w width
	 * @param h height
	 * @param type element type
	 */
	public RectArray(int w, int h, Class<T> type) {
		width = w;
		height = h;
		elements = ArrayUtil.newArrayOf(type, w * h);
	}

	/**
	 * Returns the element at the specified coords. You should prefer this to
	 * the direct access to {@link #elements} unless you are sure that the
	 * performance really matters.
	 * 
	 * @param x x coord (0 <= x < width)
	 * @param y y coord (0 <= y < height)
	 * @return element at (x, y)
	 */
	public T get(int x, int y) {
		if (cs_paramCheckEnabled) {
			ParamUtil.check(x >= 0 && x < width && y >= 0 && y < height);
		}
		return elements[x + y * width /* getLinearIndex(x, y) */];
	}

	/**
	 * Sets the element at the specified coords. You should prefer this to the
	 * direct access to {@link #elements} unless you are sure that the
	 * performance really matters.
	 * 
	 * @param x x coord (0 <= x < width)
	 * @param y y coord (0 <= y < height)
	 * @param value object to set
	 */
	public void set(int x, int y, T value) {
		if (cs_paramCheckEnabled) {
			ParamUtil.check(x >= 0 && x < width && y >= 0 && y < height);
		}
		elements[x + y * width /* getLinearIndex(x, y) */] = value;
	}

	/**
	 * Returns the linear index corresponding to the specified coords. You can
	 * use it to directly access to the specific element on {@link #elements}.
	 * The linear index is calculated by <code>x + y * width</code>.
	 * 
	 * @param x x coord (0 <= x < width)
	 * @param y y coord (0 <= y < height)
	 * @return linear index
	 */
	public int getLinearIndex(int x, int y) {
		if (cs_paramCheckEnabled) {
			ParamUtil.check(x >= 0 && x < width && y >= 0 && y < height);
		}
		return x + y * width;
	}

}
